#import "RNFilteringArrayController.h"
#import "RNItem.h"
#import "NSString+SRAdditions.h"

typedef enum {
    RNItemDevoidOfFilterString,
    RNItemContainsFilterString,
    RNItemContainsWordBeginningWithFilterString,
    RNItemFirstWordBeginsWithFilterString,
    RNItemContainsWholeWordEqualToFilterString,
    RNItemFirstWordEqualToFilterString,
    RNItemEqualsFilterString
} RNConfidence;


@interface RNFilteringArrayController (RNFilteringArrayControllerPrivateMethods)
-(RNConfidence)confidenceOfTitleString_:(NSString *)titleString withFilterString:(NSString *)currentFilterString;
@end


@implementation RNFilteringArrayController

@synthesize filterString = filterString_;
//@synthesize currentItems = currentItems_;
//@synthesize maxItems = maxItems_;
//@synthesize excessItems = excessItems_;
@synthesize punctuationAndWhitespaceCharacterSet = punctuationAndWhitespaceCharacterSet_;

-(NSCharacterSet *)punctuationAndWhitespaceCharacterSet {
    if (!punctuationAndWhitespaceCharacterSet_) {
        NSMutableCharacterSet *charSet = [[NSCharacterSet punctuationCharacterSet] mutableCopy];
        [charSet formUnionWithCharacterSet:[NSCharacterSet whitespaceCharacterSet]];
        punctuationAndWhitespaceCharacterSet_ = (NSCharacterSet *)charSet;
    }
    return punctuationAndWhitespaceCharacterSet_;
}

//-(void)filterWithString:(NSString *)string withCurrentItems:(NSArray *)currentItems {
-(void)filterWithString:(NSString *)string {
    [self setFilterString:string];
//    [self setCurrentItems:currentItems];
    [self rearrangeObjects];
}

-(NSArray *)arrangeObjects:(NSArray *)objects {
    if (![self filterString] || [[self filterString] length] == 0)
        return [NSArray array];

    
    NSMutableArray *mutableObjects = [NSMutableArray array];
    for (RNItem *item in objects) {
        NSArray *substringArray = [[self filterString] componentsSeparatedByCharactersInSet:[self punctuationAndWhitespaceCharacterSet]];
        RNConfidence confidence = 0;
        for (NSString *substring in substringArray) {
            if ([substring length] == 0)
                continue;
            confidence += [self confidenceOfTitleString_:[item title] withFilterString:substring];
        }
        if (confidence == RNItemDevoidOfFilterString)
            continue;
        [item setConfidence:[NSNumber numberWithUnsignedInteger:confidence]];
        [mutableObjects addObject:item];
    }
    
    [mutableObjects sortUsingDescriptors:[self sortDescriptors]];
    return mutableObjects;
}

-(RNConfidence)confidenceOfTitleString_:(NSString *)titleString withFilterString:(NSString *)currentFilterString {
    NSString *title = [titleString lowercaseString];
    NSString *filterString = [currentFilterString lowercaseString];
    NSUInteger filterStringIndex = 0;
    NSUInteger filterStringLength = [filterString length];
    NSUInteger titleLength = [title length];
    NSInteger indexOfCurrentWord = -1;
//    NSInteger indexOfContainedWord = -1;
    NSUInteger bestConfidence = RNItemDevoidOfFilterString;
    
    for (NSUInteger titleIndex = 0; titleIndex < titleLength; titleIndex++) {
        unichar currentTitleChar = [title characterAtIndex:titleIndex];
        if (currentTitleChar != [filterString characterAtIndex:filterStringIndex]) {
            if (indexOfCurrentWord != -1) {
                indexOfCurrentWord = -1;
                filterStringIndex = 0;
            }
            continue;
        }
        
        // Found a matching letter
        if (indexOfCurrentWord == -1)
            indexOfCurrentWord = titleIndex;

        if (filterStringIndex != (filterStringLength - 1)) {
            filterStringIndex++;
            continue;
        }

        // --------Found the whole filter string--------
            
        // At the end of the title string
        if (titleIndex == (titleLength - 1)) {
            if (indexOfCurrentWord == 0)
                return RNItemEqualsFilterString;
            if ([title characterAtIndex:(indexOfCurrentWord - 1)] == ' ')
                return fmax(RNItemContainsWholeWordEqualToFilterString, bestConfidence) ;
            return fmax(bestConfidence, RNItemContainsFilterString) ;
        }
        // Found the whole filter string, followed by a space (assumed to have found a whole word)
        if ([title characterAtIndex:(titleIndex + 1)] == ' ') {
            if (indexOfCurrentWord == 0)
                bestConfidence = RNItemFirstWordEqualToFilterString;
            else if ([title characterAtIndex:(indexOfCurrentWord - 1)] == ' ')
                bestConfidence = fmax(bestConfidence, RNItemContainsWholeWordEqualToFilterString);
            else
                bestConfidence = fmax(bestConfidence, RNItemContainsFilterString);
        }
        // Found the filter string within the title string
        else {
            if (indexOfCurrentWord == 0)
                bestConfidence = RNItemFirstWordBeginsWithFilterString;
            else if ([title characterAtIndex:(indexOfCurrentWord - 1)] == ' ')
                bestConfidence = fmax(bestConfidence, RNItemContainsWordBeginningWithFilterString);
            else
                bestConfidence = fmax(bestConfidence, RNItemContainsFilterString);
        }

//            return (indexOfCurrentWord == 0 ? RNItemFirstWordEqualToFilterString : RNItemContainsWholeWordEqualToFilterString);
        
        // Save index of the contained word and reset search term
//        if (indexOfContainedWord == -1)
//            indexOfContainedWord = indexOfCurrentWord;
        indexOfCurrentWord = -1;
        filterStringIndex = 0;
    }

    return bestConfidence;
    // Never found the whole filter string
//    if (indexOfContainedWord == 0)
//        return RNItemFirstWordBeginsWithFilterString;
//    if (indexOfContainedWord != -1)
//        return ([title characterAtIndex:(indexOfContainedWord - 1)] == ' ' ? RNItemContainsWordBeginningWithFilterString : RNItemContainsFilterString);
//    
//    return RNItemDevoidOfFilterString;
}

@end
